#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

static const int g_sockfd = -1; // 缺省的监听套接字
class TcpClient
{
public:
    TcpClient(std::string ip, uint16_t port)
        : _sockfd(g_sockfd), _server_ip(ip), _server_port(port)
    {
    }

    void InitClient()
    {
        // 1、创建套接字
        _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd < 0)
        {
            std::cerr << "sockfd create error" << std::endl;
            exit(1);
        }

        // 2、填充 server的ip和端口号
        memset(&_server, 0, sizeof(_server));                      // 清空/初始化
        _server.sin_family = AF_INET;                              // 通信类型Ipv4
        _server.sin_port = htons(_server_port);                    // 主机转网络序列
        inet_pton(AF_INET, _server_ip.c_str(), &_server.sin_addr); // 将点分十进制的ip地址转为整数

        // 3、获取连接
        int cnt = 5; // 模拟重连的次数
        while (cnt)
        {
            int n = ::connect(_sockfd, (struct sockaddr *)&_server, sizeof(_server));
            if (n == 0)
            {
                break; // 连接成功
            }

            // 连接失败，尝试进行重连
            std::cout << "连接失败，正在进行重连... 剩余次数：" << --cnt << std::endl;
            sleep(1); // 休眠一秒，给网络恢复的时间
        }
        // 连接失败
        if (cnt == 0)
        {
            std::cerr << "连接失败！" << std::endl;
            ::close(_sockfd);
            ; // 关闭掉fd防止泄漏
            exit(1);
        }
        std::cout << "连接成功！" << std::endl;
    }

    void StartClient()
    {
        char buffer[1024];
        while (true)
        {
            std::cout << "Please Enter# ";
            std::string message;
            std::getline(std::cin, message);

            // 向服务器发送请求
            ssize_t n = ::write(_sockfd, message.c_str(), message.size());
            if (n < 0)
            {
                std::cerr << "write error" << std::endl;
                break;
            }
            // 接收响应
            n = ::read(_sockfd, buffer, sizeof(buffer) - 1);
            if (n > 0)
            {
                buffer[n] = 0;
                std::cout << buffer << std::endl;
            }
            else if (n == 0)
            {
                std::cerr << "read the end of file" << std::endl;
                break;
            }
            else
            {
                std::cerr << "read error" << std::endl;
                break;
            }
        }
    }

    ~TcpClient()
    {
        if (_sockfd > g_sockfd)
            ::close(_sockfd);
    }

private:
    int _sockfd;                // 套接字文件描述符
    uint16_t _server_port;      // 服务端端口号
    std::string _server_ip;     // 服务端 ip
    struct sockaddr_in _server; // 存储服务端信息的结构体
};
